package com.sunda.spmsoversea.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmsoversea.dto.OverseaOtherDTO;
import com.sunda.spmsoversea.dto.OverseaOtherSearchDTO;
import com.sunda.spmsoversea.dto.OverseaOtherUpdateDTO;
import com.sunda.spmsoversea.entity.OverseaOtherDtl;
import com.sunda.spmsoversea.entity.OverseaOtherTask;
import com.sunda.spmsoversea.entity.WhsStorageInventory;
import com.sunda.spmsoversea.mapper.OverseaOtherTaskMapper;
import com.sunda.spmsoversea.service.*;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import static com.sunda.spmsoversea.constant.CommonConstant.SUCCESS;
import static com.sunda.spmsoversea.constant.CommonConstant.sapLog;
import static com.sunda.spmsoversea.constant.OverseaOtherTaskConstant.*;
import static com.sunda.spmsoversea.constant.SapConstant.SAP_SUCCESS;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.*;
import static com.sunda.spmsoversea.enums.OverseaDnEnum.DN_DELETE;
import static com.sunda.spmsoversea.enums.OverseaOtherEnum.*;

/**
 * <p>
 * 海外仓其他出入库 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-12-27
 */
@Service
@Slf4j
public class OverseaOtherTaskServiceImpl extends ServiceImpl<OverseaOtherTaskMapper, OverseaOtherTask> implements IOverseaOtherTaskService {

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    IFormatDataToSapService iFormatDataToSapService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IOverseaOtherDtlService iOverseaOtherDtlService;

    /** 获取其他出入库表头分页列表 */
    @Override
    public IPage getOtherTaskPage(OverseaOtherSearchDTO overseaOtherSearchDTO) {
        IPage iPage = overseaOtherSearchDTO.getPage();
        List<Map<String, Object>> mapList = this.baseMapper.getOtherTaskPage(iPage, overseaOtherSearchDTO);
        iPage.setRecords(mapList);
        return iPage;
    }

    /** 获取其他出入库表头信息 */
    @Override
    public OverseaOtherTask getOtherTask(String uuid) {
        if (StringUtils.isEmpty(uuid)){
            return null;
        }
        return this.baseMapper.selectOne(new QueryWrapper<OverseaOtherTask>().eq("UUID", uuid));
    }

    /** 获取其他出入库表头详细信息 */
    @Override
    public Map<String, Object> getOtherTaskInfo(String uuid) {
        return this.baseMapper.getOtherTaskInfo(uuid);
    }

    /** 获取其他出入库详细明细信息 */
    @Override
    public List<Map<String, Object>> getOtherDtlList(String uuid) {
        return iOverseaOtherDtlService.getOtherDtlList(uuid);
    }

    /** 其他出入库任务关闭 */
    @Override
    public ResponseResult closeOtherTask(String uuid, Integer dataVersion, String userId) {
        if (StringUtils.isEmpty(uuid) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        QueryWrapper<OverseaOtherTask> queryWrapper = new QueryWrapper<OverseaOtherTask>().eq("UUID", uuid);
        OverseaOtherTask overseaOtherTask = this.baseMapper.selectOne(queryWrapper);
        if (overseaOtherTask == null){
            return ResponseResult.error("请求其他出入库任务不存在");
        }
        if (!overseaOtherTask.getDataVersion().equals(dataVersion)){
            return ResponseResult.error("其他出入库任务信息已更新请刷新后重试");
        }
        String spmsStatus = overseaOtherTask.getSpmsStatus();
        if (!spmsStatus.equals(OTHER_SAVE.getCode()) && !spmsStatus.equals(OTHER_REJECT.getCode())){
            return ResponseResult.error("其他出入库任务当前状态禁止此操作");
        }
        overseaOtherTask.setSpmsStatus(OTHER_CLOSE.getCode());
        this.baseMapper.update(overseaOtherTask, queryWrapper);

        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, DN_DELETE.getDescZh(), DN_DELETE.getDescEn(), "");
        return ResponseResult.success("其他出入库任务关闭成功")
                .add("otherTask", getOtherTaskInfo(uuid));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult createOtherTask(OverseaOtherDTO overseaOtherDTO, String userId) {
        try {
            ResponseResult checkResult = checkCreate(overseaOtherDTO);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            String uuid = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();

            int createOtherTask =  createOverseaOtherTask(uuid, overseaOtherDTO, userId);
            if (createOtherTask < 1){
                log.info("=======createOverseaOtherTask RuntimeException=========\n");
                throw new RuntimeException("创建其他出入库任务错误");
            }

            int createOtherDtl = createOtherDtl(uuid, overseaOtherDTO);
            if (createOtherDtl < 1){
                log.info("=======createOtherDtl RuntimeException=========\n");
                throw new RuntimeException("创建其他出入库任务行项目错误");
            }
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_CREATE.getDescZh(), OTHER_CREATE.getDescEn(), "");
            return ResponseResult.success("其他出入库任务创建成功")
                    .add("otherTask", getOtherTaskInfo(uuid))
                    .add("otherDtlList", getOtherDtlList(uuid));
        } catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    ResponseResult checkCreate(OverseaOtherDTO overseaOtherDTO){
        if (overseaOtherDTO == null){
            return ResponseResult.error("请求参数不能为空");
        }
        String movementType = overseaOtherDTO.getMovementType();
        String spmsStatus = overseaOtherDTO.getSpmsStatus();
        String werks = overseaOtherDTO.getWerks();
        String whsLocationCode = overseaOtherDTO.getWhsLocationCode();
        String createDate = overseaOtherDTO.getCreateDate();
        List<OverseaOtherDtl> otherDtlList = overseaOtherDTO.getOtherDtlList();

        if (StringUtils.isEmpty(movementType)){
            return ResponseResult.error("其他出入库任务移动类型不能为空");
        }
        if (StringUtils.isEmpty(spmsStatus)){
            return ResponseResult.error("其他出入库任务目标状态不能为空");
        }
        if (StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode)){
            return ResponseResult.error("其他出入库任务工厂和仓库不能为空");
        }
        if (StringUtils.isEmpty(createDate)){
            return ResponseResult.error("其他出入库任务创建日期不能为空");
        }
        if (otherDtlList == null || otherDtlList.size() == 0){
            return ResponseResult.error("其他出入库任务明细行不能为空");
        }
        // 领用出库冲销业务，按其他出入库任务实现，新增以下 17 种领用冲销移动类型 ——— 20220121
        // 新增移动类型 建安固定资产领用Z57;建安固定资产领用撤销Z58; ———— 20220307
        if (!M_551.equals(movementType) && !M_Z56.equals(movementType) && !M_Z55.equals(movementType) &&
                !M_Z16.equals(movementType) && !M_309.equals(movementType) && !M_Z13.equals(movementType) &&
                !M_Z47.equals(movementType) && !M_561.equals(movementType) && !M_562.equals(movementType) &&

                !M_Z08.equals(movementType) && !M_Z10.equals(movementType) && !M_Z12.equals(movementType) &&
                !M_Z14.equals(movementType) && !M_Z18.equals(movementType) && !M_Z22.equals(movementType) &&
                !M_Z30.equals(movementType) && !M_Z42.equals(movementType) && !M_Z44.equals(movementType) &&
                !M_Z58.equals(movementType) && !M_Z62.equals(movementType) && !M_Z66.equals(movementType) &&
                !M_Z68.equals(movementType) && !M_Z70.equals(movementType) && !M_Z72.equals(movementType) &&
                !M_Z74.equals(movementType) && !M_Z80.equals(movementType) &&

                !M_Z57.equals(movementType)){
            return ResponseResult.error("请求移动类型错误");
        }
        /** 收货多收Z16，需要校验输入交货单号等信息 */
        if (M_Z16.equals(movementType)){
            if (StringUtils.isEmpty(overseaOtherDTO.getSapDeliveryNote())){
                return ResponseResult.error("收货多收Z16，交货单号不允许为空");
            }
        }
        /** 串货调整309，需校验输入调整前后物料编号都有值 */
        if (M_309.equals(movementType)){

        }
        return ResponseResult.success();
    }

    int createOverseaOtherTask(String uuid, OverseaOtherDTO overseaOtherDTO, String userId){
        OverseaOtherTask overseaOtherTask = new OverseaOtherTask();
        overseaOtherTask.setUuid(uuid);
        overseaOtherTask.setOperateTitle(overseaOtherDTO.getOperateTitle());
        overseaOtherTask.setMovementType(overseaOtherDTO.getMovementType());
        overseaOtherTask.setSpmsStatus(overseaOtherDTO.getSpmsStatus());
        overseaOtherTask.setWerks(overseaOtherDTO.getWerks());
        overseaOtherTask.setWorkshopCode(overseaOtherDTO.getWorkshopCode());
        overseaOtherTask.setWhsLocationCode(overseaOtherDTO.getWhsLocationCode());
        overseaOtherTask.setCreateDate(overseaOtherDTO.getCreateDate());
        overseaOtherTask.setSapDeliveryNote(overseaOtherDTO.getSapDeliveryNote());
        overseaOtherTask.setCreateUserid(userId);
        overseaOtherTask.setCostCenter(overseaOtherDTO.getCostCenter());
        overseaOtherTask.setRemarks(overseaOtherDTO.getRemarks());
        overseaOtherTask.setComments(overseaOtherDTO.getComments());
        return this.baseMapper.insert(overseaOtherTask);
    }

    int createOtherDtl(String uuid, OverseaOtherDTO overseaOtherDTO){
        String werks = overseaOtherDTO.getWerks();
        String workshopCode = overseaOtherDTO.getWorkshopCode();
        String whsLocationCode = overseaOtherDTO.getWhsLocationCode();
        String costCenter = overseaOtherDTO.getCostCenter();
        String sapDeliveryNote = overseaOtherDTO.getSapDeliveryNote();
        List<OverseaOtherDtl> otherDtlList = overseaOtherDTO.getOtherDtlList();
        int i = 0;
        for (OverseaOtherDtl otherDtl : otherDtlList){
            OverseaOtherDtl overseaOtherDtl = new OverseaOtherDtl();
            overseaOtherDtl.setUuid(uuid);
            overseaOtherDtl.setItem(String.valueOf((i + 1) * 10));
            overseaOtherDtl.setWerks(werks);
            overseaOtherDtl.setWorkshopCode(workshopCode);
            overseaOtherDtl.setWhsLocationCode(whsLocationCode);
            overseaOtherDtl.setMaterialNo(otherDtl.getMaterialNo());
            overseaOtherDtl.setActualQtyBasicUnit(otherDtl.getActualQtyBasicUnit());
            overseaOtherDtl.setStorageInfo(otherDtl.getStorageInfo());
            overseaOtherDtl.setBasicUnit(otherDtl.getBasicUnit());
            overseaOtherDtl.setCostCenter(costCenter);
            overseaOtherDtl.setMaterialNoAdjusted(otherDtl.getMaterialNoAdjusted());
            overseaOtherDtl.setActualQtyBasicUnitAdjusted(otherDtl.getActualQtyBasicUnitAdjusted());
            overseaOtherDtl.setStorageInfoAdjusted(otherDtl.getStorageInfoAdjusted());
            overseaOtherDtl.setSupplierNo(otherDtl.getSupplierNo());
            overseaOtherDtl.setSapDeliveryNote(sapDeliveryNote);
            overseaOtherDtl.setSapDeliveryNoteItem(otherDtl.getSapDeliveryNoteItem());
            overseaOtherDtl.setRemarks(otherDtl.getRemarks());
            overseaOtherDtl.setComments(otherDtl.getComments());

            overseaOtherDtl.setInternalOrderNumber(otherDtl.getInternalOrderNumber());
            overseaOtherDtl.setLocalCurrency(otherDtl.getLocalCurrency());
            if (iOverseaOtherDtlService.save(overseaOtherDtl)){
                i ++;
            }
        }
        return i;
    }

    /**
     1-1；保存修改
     1-2；提交审批：更新单据状态备注等信息，更新明细数量储位备注等信息；
     2-4；审批通过：更新单据状态，按行扣减/增加仓库库存；
     3-4；审批通过
     spmsStatus：SPMS状态(0已删除;1保存;2提交/待审批;3审批不通过;4审批通过;5提交SAP失败;6提交SAP成功;)
     movementType：报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58;
     出库 551, Z13, Z47, Z55, 562, Z57
     入库 Z56, Z16, 561
     有出有入 309

     领用出库冲销17种移动类型，增加库存：
     M_Z08, M_Z10, M_Z12, M_Z14, M_Z18, M_Z22, M_Z30, M_Z42, M_Z44, M_Z58, M_Z62, M_Z66, M_Z68, M_Z70, M_Z72, M_Z74, M_Z80
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult updateOtherTask(OverseaOtherUpdateDTO overseaOtherUpdateDTO, String userId) {
        try {
            ResponseResult checkResult = checkUpdate(overseaOtherUpdateDTO);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            String uuid = overseaOtherUpdateDTO.getUuid();
            String targetStatus = overseaOtherUpdateDTO.getSpmsStatus();

            int updateOtherTask = updateOverseaOtherTask(overseaOtherUpdateDTO);
            if (updateOtherTask < 1){
                log.info("=======updateOverseaOtherTask RuntimeException=========\n");
                throw new RuntimeException("更新其他出入库任务表错误");
            }

            int updateOtherDtl = updateOverseaOtherDtl(overseaOtherUpdateDTO);
            if (updateOtherDtl < 1){
                log.info("=======updateOverseaOtherDtl RuntimeException=========\n");
                throw new RuntimeException("更新其他出入库任务明细表错误");
            }

            /** 审批通过，目标状态为 4 时需扣除或增加对应库存 */
            if (OTHER_APPROVED.getCode().equals(targetStatus)){
                ResponseResult updateStorageInventory = updateWhsStorageInventory(uuid, userId);
                if (updateStorageInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateStorageInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateStorageInventory.getMsg());
                }
            }

            if (OTHER_SAVE.getCode().equals(targetStatus)){
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_SAVE.getDescZh(), OTHER_SAVE.getDescEn(), "");
            }
            if (OTHER_SUBMITTED.getCode().equals(targetStatus)){
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_SUBMITTED.getDescZh(), OTHER_SUBMITTED.getDescEn(), "");
            }
            if (OTHER_APPROVED.getCode().equals(targetStatus)){
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_APPROVED.getDescZh(), OTHER_APPROVED.getDescEn(), "");
            }
            return ResponseResult.success("其他出入库任务更新成功")
                    .add("otherTask", getOtherTaskInfo(uuid))
                    .add("otherDtlList", getOtherDtlList(uuid));
        } catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /**
     1-1；保存修改
     1-2；提交审批：更新单据状态备注等信息，更新明细数量储位备注等信息；
     2-4；审批通过：更新单据状态，按行扣减/增加仓库库存；
     spmsStatus：SPMS状态(0已删除;1保存;2提交/待审批;3审批不通过;4审批通过;5提交SAP失败;6提交SAP成功;)
     movementType：报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58;
     出库 551, Z13, Z47, Z55, 562, Z57
     入库 Z56, Z16, 561
     有出有入 309

     领用出库冲销17种移动类型，增加库存：
     M_Z08, M_Z10, M_Z12, M_Z14, M_Z18, M_Z22, M_Z30, M_Z42, M_Z44, M_Z58, M_Z62, M_Z66, M_Z68, M_Z70, M_Z72, M_Z74, M_Z80
     */
    synchronized ResponseResult updateWhsStorageInventory(String uuid, String userId){
        OverseaOtherTask otherTask = getOtherTask(uuid);
        List<OverseaOtherDtl> otherDtlList = iOverseaOtherDtlService.getOverseaOtherDtlList(uuid);
        String werks = otherTask.getWerks();
        String whsLocationCode = otherTask.getWhsLocationCode();
        String movementType = otherTask.getMovementType();
        if (M_551.equals(movementType) || M_Z13.equals(movementType) || M_Z47.equals(movementType)
                || M_Z55.equals(movementType) || M_562.equals(movementType)|| M_Z57.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58; **/
                            String comments = M_551.equals(movementType) ? "报废出库" :  M_Z13.equals(movementType) ? "不可抗力出库" :
                                            M_Z47.equals(movementType) ? "IT专用出库" : M_Z55.equals(movementType) ? "零价格出库" :
                                                    M_562.equals(movementType) ? "期初库存减少" : M_Z57.equals(movementType) ? "建安固定资产领用" : "其它出库";

                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓其他出入库", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        if (M_Z56.equals(movementType) || M_Z16.equals(movementType) || M_561.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58; **/
                            String comments = M_Z56.equals(movementType) ? "零价格入库" :  M_Z16.equals(movementType) ? "收货多收" :
                                    M_561.equals(movementType) ? "期初库存增加" : "其它入库";

                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓其他出入库", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        //领用出库冲销17种移动类型，增加库存：M_Z08, M_Z10, M_Z12, M_Z14, M_Z18, M_Z22, M_Z30, M_Z42, M_Z44, M_Z58, M_Z62, M_Z66, M_Z68, M_Z70, M_Z72, M_Z74, M_Z80
        if (M_Z08.equals(movementType) || M_Z10.equals(movementType) || M_Z12.equals(movementType) || M_Z14.equals(movementType) || M_Z18.equals(movementType)
                || M_Z22.equals(movementType) || M_Z30.equals(movementType) || M_Z42.equals(movementType) || M_Z44.equals(movementType) || M_Z58.equals(movementType)
                || M_Z62.equals(movementType) || M_Z66.equals(movementType) || M_Z68.equals(movementType) || M_Z70.equals(movementType) || M_Z72.equals(movementType)
                || M_Z74.equals(movementType) || M_Z80.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 办公领用冲销Z08、样品领用冲销Z10、生活领用冲销Z12、不可抗力出库冲销Z14、检测领用冲销Z18、仓库工具领用冲销Z22、生产领用(原料及包材)冲销Z30、生产领用(燃料及动力)冲销Z42、
                             * 生产领用(备品备件)冲销Z44、建安固定资产冲销Z58、生产领用（机物料消耗)-冲销Z62、生产领用（生产耗材）-冲销Z66、车辆使用（生产）-冲销Z68、车辆维修领用（非生产）-冲销Z70、
                             * 车辆燃油领用（非生产）-冲销Z72、劳保领用-冲销Z74、生产发电领用冲销Z80 **/
                            //领用出库冲销17种移动类型，增加库存：M_Z08, M_Z10, M_Z12, M_Z14, M_Z18, M_Z22, M_Z30, M_Z42, M_Z44, M_Z58, M_Z62, M_Z66, M_Z68, M_Z70, M_Z72, M_Z74, M_Z80
                            String comments = M_Z08.equals(movementType) ? "办公领用冲销" : M_Z10.equals(movementType) ? "样品领用冲销" : M_Z12.equals(movementType) ? "生活领用冲销" :
                                    M_Z14.equals(movementType) ? "不可抗力出库冲销" : M_Z18.equals(movementType) ? "检测领用冲销" : M_Z22.equals(movementType) ? "仓库工具领用冲销" :
                                    M_Z30.equals(movementType) ? "生产领用(原料及包材)冲销" : M_Z42.equals(movementType) ? "生产领用(燃料及动力)冲销" : M_Z44.equals(movementType) ? "生产领用(备品备件)冲销" :
                                    M_Z58.equals(movementType) ? "建安固定资产冲销" : M_Z62.equals(movementType) ? "生产领用（机物料消耗)-冲销" : M_Z66.equals(movementType) ? "生产领用（生产耗材）-冲销" :
                                    M_Z68.equals(movementType) ? "车辆使用（生产）-冲销" : M_Z70.equals(movementType) ? "车辆维修领用（非生产）-冲销" : M_Z72.equals(movementType) ? "车辆燃油领用（非生产）-冲销" :
                                    M_Z74.equals(movementType) ? "劳保领用-冲销" : M_Z80.equals(movementType) ? "生产发电领用冲销" : "其它入库";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓其他出入库", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        if (M_309.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58; **/
                            String comments = "串货调整出库";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓其他出入库", werks, whsLocationCode, movementType);
                        }
                    }
                }
                String materialNoAdjusted = otherDtl.getMaterialNoAdjusted();
                double actualQtyBasicUnitAdjusted = otherDtl.getActualQtyBasicUnitAdjusted() == null ? 0 : otherDtl.getActualQtyBasicUnitAdjusted();
                if (actualQtyBasicUnitAdjusted > 0){
                    JSONArray storageInfoArrayAdjusted = JSONArray.parseArray(otherDtl.getStorageInfoAdjusted());
                    for (int i = 0; i < storageInfoArrayAdjusted.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArrayAdjusted.getJSONObject(i);
                        String storageUuidAdjusted = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuidAdjusted, materialNoAdjusted, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            String comments = "串货调整入库";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuidAdjusted, materialNoAdjusted, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓其他出入库", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    int updateOverseaOtherTask(OverseaOtherUpdateDTO overseaOtherUpdateDTO){
        OverseaOtherTask overseaOtherTask = new OverseaOtherTask();
        String uuid = overseaOtherUpdateDTO.getUuid();
        QueryWrapper<OverseaOtherTask> queryWrapper = new QueryWrapper<OverseaOtherTask>().eq("UUID", uuid);
        overseaOtherTask.setOperateTitle(overseaOtherUpdateDTO.getOperateTitle());
        overseaOtherTask.setSpmsStatus(overseaOtherUpdateDTO.getSpmsStatus());
        overseaOtherTask.setCostCenter(overseaOtherUpdateDTO.getCostCenter());
        overseaOtherTask.setRemarks(StringUtils.isEmpty(overseaOtherUpdateDTO.getRemarks()) ? "-" : overseaOtherUpdateDTO.getRemarks());
        overseaOtherTask.setComments(StringUtils.isEmpty(overseaOtherTask.getComments()) ? "-" : overseaOtherTask.getComments());
        return this.baseMapper.update(overseaOtherTask, queryWrapper);
    }

    int updateOverseaOtherDtl(OverseaOtherUpdateDTO overseaOtherUpdateDTO){
        String uuid = overseaOtherUpdateDTO.getUuid();
        String costCenter = overseaOtherUpdateDTO.getCostCenter();
        List<OverseaOtherDtl> otherDtlList = overseaOtherUpdateDTO.getOtherDtlList();
        int i = 0;
        for (OverseaOtherDtl otherDtl : otherDtlList){
            OverseaOtherDtl overseaOtherDtl = new OverseaOtherDtl();
            String item = otherDtl.getItem();
            QueryWrapper<OverseaOtherDtl> queryWrapper = new QueryWrapper<OverseaOtherDtl>().eq("UUID", uuid).eq("ITEM", item);
            overseaOtherDtl.setActualQtyBasicUnit(otherDtl.getActualQtyBasicUnit());
            overseaOtherDtl.setStorageInfo(otherDtl.getStorageInfo());
            overseaOtherDtl.setCostCenter(costCenter);
            overseaOtherDtl.setMaterialNoAdjusted(otherDtl.getMaterialNoAdjusted());
            overseaOtherDtl.setActualQtyBasicUnitAdjusted(otherDtl.getActualQtyBasicUnitAdjusted());
            overseaOtherDtl.setStorageInfoAdjusted(otherDtl.getStorageInfoAdjusted());
            overseaOtherDtl.setSupplierNo(otherDtl.getSupplierNo());
            overseaOtherDtl.setSapDeliveryNoteItem(otherDtl.getSapDeliveryNoteItem());
            overseaOtherDtl.setRemarks(StringUtils.isEmpty(otherDtl.getRemarks()) ? "-" : otherDtl.getRemarks());
            overseaOtherDtl.setComments(StringUtils.isEmpty(otherDtl.getComments()) ? "-" : otherDtl.getComments());

            overseaOtherDtl.setInternalOrderNumber(otherDtl.getInternalOrderNumber());
            overseaOtherDtl.setLocalCurrency(otherDtl.getLocalCurrency());
            if (iOverseaOtherDtlService.update(overseaOtherDtl, queryWrapper)){
                i ++;
            }
        }
        return i;
    }

    /***
     1-1；保存修改
     1-2；提交审批：更新单据状态备注等信息，更新明细数量储位备注等信息；—— 出库操作需检查库存是否够扣
     2-4；审批通过：更新单据状态，按行扣减/增加仓库库存；—— 出库操作需检查库存是否够扣
     出库 551, Z13, Z47, Z55, 562, Z57
     入库 Z56, Z16, 561
     有出有入 309
     */
    ResponseResult checkUpdate(OverseaOtherUpdateDTO overseaOtherUpdateDTO){
        if (overseaOtherUpdateDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String targetStatus = overseaOtherUpdateDTO.getSpmsStatus();
        if (StringUtils.isEmpty(targetStatus)){
            return ResponseResult.error("请求参数目标状态错误");
        }
        String uuid = overseaOtherUpdateDTO.getUuid();
        if (StringUtils.isEmpty(uuid)){
            return ResponseResult.error("请求其他出入库任务参数uuid不能为空");
        }
        OverseaOtherTask overseaOtherTask = getOtherTask(uuid);
        if (!overseaOtherTask.getDataVersion().equals(overseaOtherUpdateDTO.getDataVersion())){
            return ResponseResult.error("其他出入库任务信息已更新请刷新后重试");
        }
        String spmsId = overseaOtherTask.getSpmsId();
        String currentStatus = overseaOtherTask.getSpmsStatus();
        String movementType = overseaOtherTask.getMovementType();
        List<OverseaOtherDtl> otherDtlList = overseaOtherUpdateDTO.getOtherDtlList();
        if (!OTHER_SAVE.getCode().equals(currentStatus) && !OTHER_SUBMITTED.getCode().equals(currentStatus)
                && !OTHER_REJECT.getCode().equals(currentStatus)){
            return ResponseResult.error("其他出入库任务当前状态禁止此操作");
        }
        if (OTHER_SAVE.getCode().equals(targetStatus)){

        } else if (OTHER_SUBMITTED.getCode().equals(targetStatus) || OTHER_APPROVED.getCode().equals(targetStatus)){
            if (M_551.equals(movementType) || M_Z13.equals(movementType) || M_Z47.equals(movementType) ||
                    M_Z55.equals(movementType) || M_562.equals(movementType) || M_Z57.equals(movementType) ||
                    M_309.equals(movementType)){
                //提交审批 1-2，或 审批通过 2-4，有库存扣减的操作，需要检查单据明细行每行物料库存是否够扣减；
                for (OverseaOtherDtl otherDtl : otherDtlList){
                    String item = otherDtl.getItem();
                    String materialNo = otherDtl.getMaterialNo();
                    String storageInfo = otherDtl.getStorageInfo();
                    double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit();
                    if (actualQtyBasicUnit > 0){
                        if (StringUtils.isEmpty(storageInfo)){
                            return ResponseResult.error(spmsId + "实出数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                        }
                        //storageInfoArray 结构参考：[{"storageUuid":"cbd9576a4e53461fe0530101007f3e24","qty":5,"storageNo":"A010101","unitValue":5}]
                        JSONArray storageInfoArray = JSONArray.parseArray(storageInfo);
                        for (int i = 0; i < storageInfoArray.size(); i ++){
                            JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                            String storageUuid = storageInfoObj.getString("storageUuid");
                            double qty = storageInfoObj.getDoubleValue("qty");
                            String storageNo = storageInfoObj.getString("storageNo");
                            if (qty > 0){
                                WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                                if (whsStorageInventory == null){
                                    return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                                }
                                if (qty > whsStorageInventory.getAvailableQty()){
                                    return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                                }
                            }
                        }
                    }
                }
            }
        } else {
            return ResponseResult.error("其他出入库任务请求目标状态错误");
        }
        return ResponseResult.success();
    }

    /** 新增明细行 */
    @Override
    public synchronized ResponseResult updateOtherDtlListI(List<OverseaOtherDtl> otherDtlList, String userId) {
        if (otherDtlList == null || otherDtlList.size() == 0){
            return ResponseResult.error("请求参数错误");
        }
        String uuid = otherDtlList.get(0).getUuid();
        OverseaOtherTask overseaOtherTask = getOtherTask(uuid);
        if (overseaOtherTask == null){
            return ResponseResult.error("请求其他出入库任务不存在");
        }
        Integer maxItemNumber = this.baseMapper.getOtherTaskMaxItemNumber(uuid);
        for (int i = 0; i < otherDtlList.size(); i ++){
            OverseaOtherDtl otherDtl = otherDtlList.get(i);
            otherDtl.setUuid(uuid);
            otherDtl.setItem(String.valueOf((i + 1) * 10 + maxItemNumber));
            otherDtl.setWerks(overseaOtherTask.getWerks());
            otherDtl.setWhsLocationCode(overseaOtherTask.getWhsLocationCode());
            otherDtl.setWorkshopCode(overseaOtherTask.getWorkshopCode());
            otherDtl.setCostCenter(overseaOtherTask.getCostCenter());
            iOverseaOtherDtlService.save(otherDtl);
        }
        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_UPDATE.getDescZh(), OTHER_UPDATE.getDescEn(), "");
        return ResponseResult.success("其他出入库任务明细更新成功").add("otherDtlList", getOtherDtlList(uuid));
    }

    /** 删除明细行 */
    @Override
    public synchronized ResponseResult updateOtherDtlListD(List<OverseaOtherDtl> otherDtlList, String userId) {
        if (otherDtlList == null || otherDtlList.size() == 0){
            return ResponseResult.error("请求参数错误");
        }
        String uuid = "";
        for (OverseaOtherDtl otherDtl : otherDtlList){
            uuid = otherDtl.getUuid();
            String item = otherDtl.getItem();
            if (StringUtils.isNotEmpty(uuid) && StringUtils.isNotEmpty(item)){
                QueryWrapper<OverseaOtherDtl> queryWrapper = new QueryWrapper<OverseaOtherDtl>().eq("UUID", uuid).eq("ITEM", item);
                iOverseaOtherDtlService.remove(queryWrapper);
            }
        }
        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_UPDATE.getDescZh(), OTHER_UPDATE.getDescEn(), "");
        return ResponseResult.success("其他出入库任务明细更新成功").add("otherDtlList", getOtherDtlList(uuid));
    }

    /** 提交SAP；4-5/6、5-5/6 */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult submitOtherTaskSap(String uuid, String costCenter, String postingDate, Integer dataVersion, String userId) {
        try {
            ResponseResult checkResult = checkToSap(uuid, costCenter, postingDate, dataVersion);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            QueryWrapper<OverseaOtherTask> queryWrapper = new QueryWrapper<OverseaOtherTask>().eq("UUID", uuid);
            OverseaOtherTask overseaOtherTask = getOtherTask(uuid);

            Map<String, Object> otherTaskHead = this.baseMapper.otherTaskHead(uuid, postingDate);
            List<Map<String, Object>> otherDtlItem = this.baseMapper.otherDtlItem(uuid, StringUtils.isEmpty(costCenter) || "null".equals(costCenter.trim()) ? "" : costCenter);
            if (otherTaskHead == null || otherDtlItem == null || otherDtlItem.size() == 0){
                return ResponseResult.error("查询无可提交SAP项目");
            }
            JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(otherTaskHead, otherDtlItem, "Z_SPMS_ANOMALY_POST", "ANOMALY_POST");
            log.info("=======其他出入库任务 成本中心出入库请求SAP dataToSap=========\n" + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("=======其他出入库任务 成本中心出入库请求SAP响应结果 message=========\n" + message);
            JSONObject RETURN_DATA_Undercharged = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            if (SAP_SUCCESS.equals(RETURN_DATA_Undercharged.getString("O_TYPE"))) {
                String sapVoucherNumber = RETURN_DATA_Undercharged.getString("O_MBLNR").trim();
                String sapVoucherYear = RETURN_DATA_Undercharged.getString("O_MJAHR").trim();
                overseaOtherTask.setPostingDate(postingDate);
                if (StringUtils.isNotEmpty(costCenter) && !"null".equals(costCenter.trim())){
                    overseaOtherTask.setCostCenter(costCenter);
                }
                overseaOtherTask.setSapVoucherNumber(sapVoucherNumber);
                overseaOtherTask.setSapVoucherYear(sapVoucherYear);
                overseaOtherTask.setSpmsStatus(OTHER_SUBMIT_SAP.getCode());
                this.baseMapper.update(overseaOtherTask, queryWrapper);

                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_SUBMIT_SAP.getDescZh() + ":" + sapVoucherNumber,
                        OTHER_SUBMIT_SAP.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "其他出入库提交SAP成功");
                return ResponseResult.success("其他出入库任务提交SAP成功").add("otherTask", getOtherTaskInfo(uuid));
            } else {
                overseaOtherTask.setPostingDate(postingDate);
                overseaOtherTask.setCostCenter(costCenter);
                overseaOtherTask.setSpmsStatus(OTHER_SUBMIT_SAP_ERROR.getCode());
                this.baseMapper.update(overseaOtherTask, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_SUBMIT_SAP_ERROR.getDescZh(),
                        OTHER_SUBMIT_SAP_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "其他出入库提交SAP失败");
                return ResponseResult.error("其他出入库任务提交SAP失败")
                        .add("sapReturnedMessage", message)
                        .add("dataToSap", dataToSap)
                        .add("otherTask", getOtherTaskInfo(uuid));
            }
        }catch (FeignException feignException){
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("其他出入库任务更新单据或提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    /**
     movementType：报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562;建安固定资产领用Z57;建安固定资产领用撤销Z58;
     出库 551, Z13, Z47, Z55, 562, Z57; 入库 Z56, Z16, 561; 有出有入 309;
     561, 562 提交SAP不需要成本中心；

     */
    ResponseResult checkToSap(String uuid, String costCenter, String postingDate, Integer dataVersion){
        if (StringUtils.isEmpty(uuid) || StringUtils.isEmpty(postingDate) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaOtherTask overseaOtherTask = getOtherTask(uuid);
        if (overseaOtherTask == null){
            return ResponseResult.error("请求其他出入库任务不存在");
        }
        if (!dataVersion.equals(overseaOtherTask.getDataVersion())){
            return ResponseResult.error("请求其他出入库任务已更新请刷新重试");
        }
        String spmsStatus = overseaOtherTask.getSpmsStatus();
        if (!OTHER_APPROVED.getCode().equals(spmsStatus) && !OTHER_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求其他出入库任务当前状态禁止此操作");
        }
        String movementType = overseaOtherTask.getMovementType();
        if (M_551.equals(movementType) || M_Z13.equals(movementType) || M_Z47.equals(movementType) || M_Z55.equals(movementType)
                || M_Z56.equals(movementType) || M_Z16.equals(movementType) || M_309.equals(movementType)){
            if (StringUtils.isEmpty(costCenter)){
                return ResponseResult.error("成本中心不允许为空");
            }
        }
        return ResponseResult.success();
    }

    /** 任务回撤；2-3(审批不通过)、6-4、4/5-1(库存操作)
     * spmsStatus：SPMS状态(0已删除;1保存;2提交/待审批;3审批不通过;4审批通过;5提交SAP失败;6提交SAP成功;)*/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult cancelOtherTask(String uuid, String cancelPostingDate, Integer dataVersion, String userId) {
        try {
            ResponseResult checkResult = checkCancel(uuid, cancelPostingDate, dataVersion);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            QueryWrapper<OverseaOtherTask> queryWrapper = new QueryWrapper<OverseaOtherTask>().eq("UUID", uuid);
            OverseaOtherTask overseaOtherTask = getOtherTask(uuid);
            String spmsStatus = overseaOtherTask.getSpmsStatus();
            if (OTHER_SUBMITTED.getCode().equals(spmsStatus)){
                overseaOtherTask.setSpmsStatus(OTHER_REJECT.getCode());
                this.baseMapper.update(overseaOtherTask, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_REJECT.getDescZh(), OTHER_REJECT.getDescEn(), "");
                return ResponseResult.success("其他出入库任务审批不通过").add("otherTask", getOtherTaskInfo(uuid));
            }else if (OTHER_SUBMIT_SAP.getCode().equals(spmsStatus)){
                Map<String, Object> dataHeadCancel = this.baseMapper.dataHeadCancel(uuid, cancelPostingDate);
                if (dataHeadCancel == null){
                    return ResponseResult.error("查询无可提交SAP项目");
                }
                JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(dataHeadCancel, null, "Z_SPMS_CANCEL", "SPMS_CANCEL");
                log.info("=======其他出入库任务撤销 请求SAP dataToSap=========\n" + dataToSap);
                JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                log.info("=======其他出入库任务撤销 请求SAP响应结果 message=========\n" + message);
                JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))){
                    String cancelVoucherNumber = RETURN_DATA.getString("0_MBLNR");
                    overseaOtherTask.setCancelPostingDate(cancelPostingDate);
                    overseaOtherTask.setCancelVoucherNumber(cancelVoucherNumber);
                    overseaOtherTask.setSpmsStatus(OTHER_APPROVED.getCode());
                    this.baseMapper.update(overseaOtherTask, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_CANCEL_TO_APPROVED.getDescZh() + ":" + cancelVoucherNumber,
                            OTHER_CANCEL_TO_APPROVED.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "其他出入库任务撤销提交SAP");
                    return ResponseResult.success("其他出入库任务撤销提交SAP成功").add("otherTask", getOtherTaskInfo(uuid));
                } else {
                    overseaOtherTask.setCancelPostingDate(cancelPostingDate);
                    this.baseMapper.update(overseaOtherTask, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_CANCEL_ERROR.getDescZh(),
                            OTHER_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "其他出入库任务撤销提交SAP");
                    return ResponseResult.error("其他出入库任务撤销提交SAP失败")
                            .add("sapReturnedMessage", message)
                            .add("dataToSap", dataToSap)
                            .add("otherTask", getOtherTaskInfo(uuid));
                }
            } else if (OTHER_APPROVED.getCode().equals(spmsStatus) || OTHER_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
                ResponseResult updateStorageInventory = cancelUpdateWhsStorageInventory(overseaOtherTask, userId);
                if (updateStorageInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateStorageInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateStorageInventory.getMsg());
                }
                overseaOtherTask.setSpmsStatus(OTHER_CANCEL_TO_SAVE.getCode());
                this.baseMapper.update(overseaOtherTask, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OTHER_CANCEL_TO_SAVE.getDescZh(), OTHER_CANCEL_TO_SAVE.getDescEn(), "");
                return ResponseResult.success("其他出入库任务撤回成功").add("otherTask", getOtherTaskInfo(uuid));
            } else {
                return ResponseResult.error("其他出入库任务当前状态禁止此操作");
            }
        }catch (FeignException feignException){
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("其他出入库任务更新单据或提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    /***
     SPMS状态(0已删除;1保存;2提交/待审批;3审批不通过;4审批通过;5提交SAP失败;6提交SAP成功;)
     2-3(审批不通过)
     6-4；撤回SAP凭证；
     4/5-1；撤回到审批通过之前，原入库类型(Z56, Z16, 309)需检查出库库存是否足够扣减；
     出库 551, Z13, Z47, Z55, 562, Z57
     入库 Z56, Z16, 561
     有出有入 309

     561, 562, Z57 禁止回撤；

     领用出库冲销17种移动类型，增加库存的操作，禁止回撤：
     M_Z08, M_Z10, M_Z12, M_Z14, M_Z18, M_Z22, M_Z30, M_Z42, M_Z44, M_Z58, M_Z62, M_Z66, M_Z68, M_Z70, M_Z72, M_Z74, M_Z80
     */
    ResponseResult checkCancel(String uuid, String cancelPostingDate, Integer dataVersion){
        if (StringUtils.isEmpty(uuid) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaOtherTask overseaOtherTask = getOtherTask(uuid);
        if (overseaOtherTask == null){
            return ResponseResult.error("请求其他出入库任务不存在");
        }
        if (!dataVersion.equals(overseaOtherTask.getDataVersion())){
            return ResponseResult.error("请求其他出入库任务已更新请刷新重试");
        }
        String movementType = overseaOtherTask.getMovementType();
        String spmsStatus = overseaOtherTask.getSpmsStatus();
        if (!OTHER_SUBMITTED.getCode().equals(spmsStatus) && !OTHER_APPROVED.getCode().equals(spmsStatus)
                && !OTHER_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus) && !OTHER_SUBMIT_SAP.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求其他出入库任务当前状态禁止此操作");
        }
        if (OTHER_SUBMIT_SAP.getCode().equals(spmsStatus)){
            if (M_561.equals(movementType) || M_562.equals(movementType)){
                return ResponseResult.error("期初数据禁止此操作");
            }
            if (M_Z57.equals(movementType)){
                return ResponseResult.error("建安固定资产领用禁止此操作");
            }
            if (M_Z08.equals(movementType) || M_Z10.equals(movementType) || M_Z12.equals(movementType) || M_Z14.equals(movementType) || M_Z18.equals(movementType)
                    || M_Z22.equals(movementType) || M_Z30.equals(movementType) || M_Z42.equals(movementType) || M_Z44.equals(movementType) || M_Z58.equals(movementType)
                    || M_Z62.equals(movementType) || M_Z66.equals(movementType) || M_Z68.equals(movementType) || M_Z70.equals(movementType) || M_Z72.equals(movementType)
                    || M_Z74.equals(movementType) || M_Z80.equals(movementType)){
                return ResponseResult.error("领用出库冲销数据禁止此操作");
            }
            if (StringUtils.isEmpty(cancelPostingDate)){
                return ResponseResult.error("撤销SAP凭证过账日期不能为空");
            }
            if (StringUtils.isEmpty(overseaOtherTask.getSapVoucherNumber())){
                return ResponseResult.error("撤销SAP凭证不存在");
            }
        }
        if (OTHER_APPROVED.getCode().equals(spmsStatus) || OTHER_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
            if (M_561.equals(movementType) || M_562.equals(movementType)){
                return ResponseResult.error("期初数据禁止此操作");
            }
            String spmsId = overseaOtherTask.getSpmsId();
            if (M_Z56.equals(movementType) || M_Z16.equals(movementType)){
                List<OverseaOtherDtl> otherDtlList = iOverseaOtherDtlService.getOverseaOtherDtlList(uuid);
                for (OverseaOtherDtl otherDtl : otherDtlList){
                    String item = otherDtl.getItem();
                    String materialNo = otherDtl.getMaterialNo();
                    String storageInfo = otherDtl.getStorageInfo();
                    double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit();
                    if (actualQtyBasicUnit > 0){
                        if (StringUtils.isEmpty(storageInfo)){
                            return ResponseResult.error(spmsId + "实出数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                        }
                        //storageInfoArray 结构参考：[{"storageUuid":"cbd9576a4e53461fe0530101007f3e24","qty":5,"storageNo":"A010101","unitValue":5}]
                        JSONArray storageInfoArray = JSONArray.parseArray(storageInfo);
                        for (int i = 0; i < storageInfoArray.size(); i ++){
                            JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                            String storageUuid = storageInfoObj.getString("storageUuid");
                            double qty = storageInfoObj.getDoubleValue("qty");
                            String storageNo = storageInfoObj.getString("storageNo");
                            if (qty > 0){
                                WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                                if (whsStorageInventory == null){
                                    return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                                }
                                if (qty > whsStorageInventory.getAvailableQty()){
                                    return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                                }
                            }
                        }
                    }
                }
            }
            if (M_309.equals(movementType)){
                List<OverseaOtherDtl> otherDtlList = iOverseaOtherDtlService.getOverseaOtherDtlList(uuid);
                for (OverseaOtherDtl otherDtl : otherDtlList){
                    String item = otherDtl.getItem();
                    String materialNo = otherDtl.getMaterialNoAdjusted();
                    String storageInfo = otherDtl.getStorageInfoAdjusted();
                    double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnitAdjusted();
                    if (actualQtyBasicUnit > 0){
                        if (StringUtils.isEmpty(storageInfo)){
                            return ResponseResult.error(spmsId + "调整数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                        }
                        //storageInfoArray 结构参考：[{"storageUuid":"cbd9576a4e53461fe0530101007f3e24","qty":5,"storageNo":"A010101","unitValue":5}]
                        JSONArray storageInfoArray = JSONArray.parseArray(storageInfo);
                        for (int i = 0; i < storageInfoArray.size(); i ++){
                            JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                            String storageUuid = storageInfoObj.getString("storageUuid");
                            double qty = storageInfoObj.getDoubleValue("qty");
                            String storageNo = storageInfoObj.getString("storageNo");
                            if (qty > 0){
                                WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                                if (whsStorageInventory == null){
                                    return ResponseResult.error("串货调整行号" + item + "物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                                }
                                if (qty > whsStorageInventory.getAvailableQty()){
                                    return ResponseResult.error("串货调整行号" + item + "物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                                }
                            }
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    synchronized ResponseResult cancelUpdateWhsStorageInventory(OverseaOtherTask otherTask, String userId){
        String uuid = otherTask.getUuid();
        String werks = otherTask.getWerks();
        String whsLocationCode = otherTask.getWhsLocationCode();
        String movementType = otherTask.getMovementType();
        List<OverseaOtherDtl> otherDtlList = iOverseaOtherDtlService.getOverseaOtherDtlList(uuid);
        if (M_551.equals(movementType) || M_Z13.equals(movementType) || M_Z47.equals(movementType) || M_Z55.equals(movementType) || M_Z57.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562; 建安固定资产领用Z57;建安固定资产领用撤销Z58;**/
                            String comments = M_551.equals(movementType) ? "报废出库撤销" :  M_Z13.equals(movementType) ? "不可抗力出库撤销" :
                                    M_Z47.equals(movementType) ? "IT专用出库撤销" : M_Z55.equals(movementType) ? "零价格出库撤销" : M_Z57.equals(movementType) ? "建安固定资产领用撤销" : "其它出库撤销";

                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓其他出入库撤销", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        if (M_Z56.equals(movementType) || M_Z16.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562; 建安固定资产领用Z57;建安固定资产领用撤销Z58;**/
                            String comments = M_Z56.equals(movementType) ? "零价格入库撤销" :  M_Z16.equals(movementType) ? "收货多收撤销" : "其它入库撤销";

                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓其他出入库撤销", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        if (M_309.equals(movementType)){
            for (OverseaOtherDtl otherDtl : otherDtlList){
                String materialNo = otherDtl.getMaterialNo();
                double actualQtyBasicUnit = otherDtl.getActualQtyBasicUnit() == null ? 0 : otherDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    JSONArray storageInfoArray = JSONArray.parseArray(otherDtl.getStorageInfo());
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 报废出库551;零价格出库Z55;零价格入库Z56;收货多收Z16;串货调整309;不可抗力出库Z13;IT专用出库Z47;期初库存增加561;期初库存减少562; 建安固定资产领用Z57;建安固定资产领用撤销Z58;**/
                            String comments = "串货调整出库撤销";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓其他出入库撤销", werks, whsLocationCode, movementType);
                        }
                    }
                }
                String materialNoAdjusted = otherDtl.getMaterialNoAdjusted();
                double actualQtyBasicUnitAdjusted = otherDtl.getActualQtyBasicUnitAdjusted() == null ? 0 : otherDtl.getActualQtyBasicUnitAdjusted();
                if (actualQtyBasicUnitAdjusted > 0){
                    JSONArray storageInfoArrayAdjusted = JSONArray.parseArray(otherDtl.getStorageInfoAdjusted());
                    for (int i = 0; i < storageInfoArrayAdjusted.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArrayAdjusted.getJSONObject(i);
                        String storageUuidAdjusted = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuidAdjusted, materialNoAdjusted, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            String comments = "串货调整入库撤销";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuidAdjusted, materialNoAdjusted, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓其他出入库撤销", werks, whsLocationCode, movementType);
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }
}


